package com.bmatch.tech.service.impl;

import com.bmatch.tech.service.UploadService;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;


/**
 * @program:FileStore
 * @author:LinJinhao
 * @create:2018-11-28 00:34
 **/

@MultipartConfig
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet implements UploadService {

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)throws ServletException,IOException {
        String result=request.getParameter("result");

        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        response.setStatus(200);
        response.getWriter().println("<form method=\"post\" action=\"/UploadServlet\" enctype=\"multipart/form-data\">\n" +
                "    选择一个文件:\n" +
                "    <input type=\"file\" name=\"uploadFile\" />\n" +
                "    <br/><br/>\n" +
                "    <input type=\"submit\" value=\"上传\" />\n" +
                "</form>");

        response.getWriter().println("<h1>"+result+"</h1>");

    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try{
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //缓冲区默认是10k,下面我们设置如果上传文件超过10k则使用一个临时文件保存
            factory.setRepository(new File(SnapPath));

            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setProgressListener(
            //这里我们定义一个监听器，可以看到文件上传的进度，之后可以使用ajax生成一个进度条,同时注意定义的位置，这里是在解析器定义之后解析完文件之前
                    new ProgressListener() {

                        @Override
                        public void update(long pBytesRead, long pContentLength, int arg2) {
                            System.out.println("文件大小为：" + pContentLength + ",当前已处理：" + pBytesRead);

                        }
                    });

            upload.setHeaderEncoding("UTF-8");//解决上传文件名在中文乱码问题

            if(!upload.isMultipartContent(request)){
                //如果不是文件上传
                //按照传统方式获取数据
                return ;
            }
            /*upload.setFileSizeMax(1024);//上传的文件不能超过1k
            upload.setSizeMax(1024*10);//上传文件的总大小不能超过10k
            */
            List<FileItem> list = upload.parseRequest(request);
            for(FileItem item : list){
                if(item.isFormField()){
                    //fileItem中封装的是普通输入项的数据
                    String name = item.getFieldName();
                    String value = item.getString("UTF-8");//也可以用这种方式制定码表
                    System.out.println(name + "=" + value);

                }else{
                    //提交的表单是上传文件，不是普通输入项
                    String filename = item.getName();
                    if(filename == null || filename.trim().equals("")){
                        continue;//如果某个框中没有选择上传的文件则跳出本次循环，继续下一次循环
                    }

                    filename = filename.substring(filename.lastIndexOf("\\") + 1);
                    InputStream in = item.getInputStream();
                    String saveFileName = makeFileName(filename);//得到文件保存的名称

                    String realSavaPath = makePath(saveFileName, StorePath);//产生目录
                    FileOutputStream out = new FileOutputStream(realSavaPath +"/" + saveFileName);
                    byte buffer[] = new byte[1024];
                    int len = 0;
                    while((len = in.read(buffer)) > 0){
                        out.write(buffer, 0, len);
                    }
                    in.close();
                    out.close();
                    item.delete();//删除临时文件,而且这行代码必须在上面流关闭的后面


                    response.sendRedirect("/?result=Success!");

                }
            }
        }catch(FileUploadBase.FileSizeLimitExceededException e){
            e.printStackTrace();

            response.sendRedirect("/?result=File is exceed!");
            return;
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    //产生唯一的文件名
    public String makeFileName(String filename){

        return UUID.randomUUID().toString() + "_" + filename;
    }
    //产生一个目录
    public String makePath(String filename, String savePath){
        int hashCode = filename.hashCode();//得到一个文件名的哈希编码，即文件在内存中的地址
        int dir1 = hashCode & 0xf;//得到一个0-15的数，表示一级目录最多有16个目录
        int dir2 = (hashCode & 0xf0) >> 4;

        String dir = savePath  + dir1 + "/" + dir2;//完整路径就是upload/2/3...
        File file = new File(dir);
        if(!file.exists()){
            file.mkdirs();//因为这里会有多级目录，则用此方法。若是只有一级目录，那使用mkdir方法
        }
        return dir;
    }
}
